singlepass聚类算法实现天气聚类 您所在的位置:网站首页 single pass聚类 singlepass聚类算法实现天气聚类

singlepass聚类算法实现天气聚类

2023-04-19 07:24| 来源: 网络整理| 查看: 265

聚类算法聚类算法介绍(1)系统聚类法(2)K-means聚类法(3)single-pass聚类法含义适用处理步骤样本描述代码实现定义类和函数调用与画图总结

聚类算法介绍 (1)系统聚类法

系统聚类法的基本思想是:距离近的样品先聚成类,距离远的后聚成类。

根据类间定义的不同,系统聚类法又可以分成最短距离法、最长距离法、中间距离法、重心法、类平均法、可变类平均法、可变法、离差平方和法8种。

需要注意的是:

(1)该方法不需要事先指定聚类个数,而是根据最终的分类过程确定。

(2)为了直观的反映,可以把分类系统画成一张谱系图,所以系统聚类也称谱系分析。

(2)K-means聚类法

K-means聚类法是非常经典的聚类算法,有关资料很丰富,故本文不再赘述。

需要注意的是:

(1)该方法通过计算欧氏距离,比较样品间的相似度进行聚类。不过我也有看过,通过计算相关系数来聚类的。

(2)该法需要指定聚类个数,而K的确定是个难点,有很多针对K优化的方法。

(3)single-pass聚类法 含义适用

Single-pass clustering,中文名一般译作“单遍聚类”,它是一种简洁且高效的文本聚类算法。相比于常用的K-means聚类法,它的计算速度非常快,且不需要指定聚类个数,而是通过设定相似度阈值来限定。

Single-pass聚类算法同时是一种增量聚类算法(Incremental Clustering Algorithm),每个文档只需要流过算法一次,常用与文本主题的聚类中。它可以很好的应用于话题监测与追踪、在线事件监测等社交媒体大数据领域,特别适合流式数据(Streaming Data),比如微博的帖子信息等。

流数据:一组顺序、大量、快速、连续到达的数据序列。一般情况下,流数据可被视为一个随时间延续而无限增长的动态数据集合。 来源:百度百科

处理步骤

Single-pass算法顺序处理文本,以第一篇文档为种子,建立一个新主题。之后再进行新进入文档与已有主题的相似度,将该文档加入到与它相似度最大的、且大于一定阈值的主题中。如果与所有已有话题相似度都小于阈值,则以该文档为聚类种子,建立新的主题类别。其算法流程如下:

(1)以第一篇文档为种子,建立一个主题;

(2)将文档X向量化;

(3)将文档X与已有的所有话题均做相似度计算,可采用欧氏距离或余弦距离等距离度量方法

(4)找出与文档X具有最大相似度的已有主题;

(5)若相似度值大于阈值θ ,则把文档X加入到有最大相似度的主题中,跳转至 (7);

(6)若相似度值小于阈值θ , 则文档X不属于任一已有主题, 需创建新的主题类别,同时将当前文本归属到新创建的主题类别中;

(7)聚类结束,等待下一篇文档进入

注:上述中讲相似度最大的划为一类,在实际代码中,所谓相似度最大大于某个阈值,也可以理解为距离最近(小)小于某个阈值。

样本描述

样本信息截图 将样本信息保存至TXT文件中,截图后如上所示。

有多少行我没数,用python中describe()一下就知道了,列数是十列。

日期后面两类是最高温和最低温,最后两列表示该地的经度和纬度。

代码实现 定义类和函数

首先定义了一个簇单元 ClusterUnit ,定义了一个单类 OnePassCluster ,定义了向量a与b间的欧式距离euclidian_distance。

# coding=utf-8import numpy as npfrom math import sqrtimport timeimport matplotlib.pylab as pl# 定义一个簇单元class ClusterUnit:def __init__(self):self.node_list = [] # 该簇存在的节点列表self.node_num = 0 # 该簇节点数self.centroid = None # 该簇质心def add_node(self, node, node_vec):"""为本簇添加指定节点,并更新簇心node_vec:该节点的特征向量node:节点return:null"""self.node_list.append(node)try:self.centroid = (self.node_num * self.centroid + node_vec) / (self.node_num + 1) # 更新簇心except TypeError:self.centroid = np.array(node_vec) * 1 # 初始化质心self.node_num += 1 # 节点数加1def remove_node(self, node):# 移除本簇指定节点try:self.node_list.remove(node)self.node_num -= 1except ValueError:raise ValueError("%s not in this cluster" % node) # 该簇本身就不存在该节点,移除失败def move_node(self, node, another_cluster):# 将本簇中的其中一个节点移至另一个簇self.remove_node(node=node)another_cluster.add_node(node=node)# cluster_unit = ClusterUnit()# cluster_unit.add_node(1, [1, 1, 2])# cluster_unit.add_node(5, [2, 1, 2])# cluster_unit.add_node(3, [3, 1, 2])# print(cluster_unit.centroid)# 计算向量a与向量b的欧式距离def euclidian_distance(vec_a, vec_b):diff = vec_a - vec_breturn sqrt(np.dot(diff, diff)) # dot计算矩阵内积class OnePassCluster:def __init__(self, t, vector_list):# t:一趟聚类的阈值self.threshold = t # 一趟聚类的阈值self.vectors = np.array(vector_list) # 数据列表(向量列表)self.cluster_list = [] # 聚类后簇的列表t1 = time.time()self.clustering()t2 = time.time()self.cluster_num = len(self.cluster_list) # 聚类完成后 簇的个数self.spend_time = t2 - t1 # 聚类花费的时间def clustering(self):self.cluster_list.append(ClusterUnit()) # 初始新建一个簇self.cluster_list[0].add_node(0, self.vectors[0]) # 将读入的第一个节点归于该簇for index in range(len(self.vectors))[1:]:min_distance = euclidian_distance(vec_a=self.vectors[index],vec_b=self.cluster_list[0].centroid) # 与簇的质心的最小距离min_cluster_index = 0 # 最小距离的簇的索引for cluster_index, cluster in enumerate(self.cluster_list[1:]):# enumerate会将数组或列表组成一个索引序列# 寻找距离最小的簇,记录下距离和对应的簇的索引distance = euclidian_distance(vec_a=self.vectors[index],vec_b=cluster.centroid)if distance min_distance:min_distance = distancemin_cluster_index = cluster_index + 1if min_distance self.threshold: # 最小距离小于阈值,则归于该簇self.cluster_list[min_cluster_index].add_node(index, self.vectors[index])else: # 否则新建一个簇new_cluster = ClusterUnit()new_cluster.add_node(index, self.vectors[index])self.cluster_list.append(new_cluster)del new_clusterdef print_result(self, label_dict=None):# 打印出聚类结果# label_dict:节点对应的标签字典print("*********** single-pass的聚类结果展示 ***********")for index, cluster in enumerate(self.cluster_list):print("cluster:%s" % index) # 簇的序号print(cluster.node_list) # 该簇的节点列表if label_dict is not None:print(" ".join([label_dict[n] for n in cluster.node_list])) # 若有提供标签字典,则输出该簇的标签print("node num: %s" % cluster.node_num)print( "-------------")print( "所有节点的个数为: %s" % len(self.vectors))print("簇类的个数为:%s" % self.cluster_num)print("花费的时间为: %.9fs" % (self.spend_time / 1000))

运行之后,一共聚类十类,聚类个数从0-9。

如下图为第八个类别所包含的城市以及他们对应的索引: 第八个类别中内容 整体运行结果如下: 运行结果

调用与画图

之后通过实例化类和调用函数,来实现聚类

# 读取测试集temperature_all_city = np.loadtxt('data1.txt', delimiter=",", usecols=(3, 4),encoding='utf-8') # 读取聚类特征xy = np.loadtxt('data1.txt', delimiter=",", usecols=(8, 9),encoding='utf-8') # 读取各地经纬度f = open('data1.txt', 'r',encoding='utf-8')lines = f.readlines()zone_dict = [i.split(',')[1] for i in lines] # 读取地区并转化为字典f.close()# 构建一趟聚类器clustering = OnePassCluster(vector_list=temperature_all_city, t=9)clustering.print_result(label_dict=zone_dict)print(temperature_all_city)# 将聚类结果导出图fig, ax = pl.subplots()fig = zone_dictc_map = pl.get_cmap('jet', clustering.cluster_num)c = 0for cluster in clustering.cluster_list:for node in cluster.node_list:#ax.scatter(xy[node][0], xy[node][1], c=c, s=30, cmap=c_map, vmin=0, vmax=clustering.cluster_num)ax.scatter(xy[node][0], xy[node][1])c += 1#pl.axis('off') # 不显示坐标轴pl.savefig('./map.jpg')pl.show()

根据样本中经纬度的信息,并结合聚类算法的结果,可画图如下: 可视化画图

总结

本文主要给出single-pass聚类算法的实例,该例很好复现。希望对各位兄弟姐妹们有所帮助。

参考:https://blog.csdn.net/maqian5/article/details/107333316

本文数据与代码均引用他处,如未标注来源,请联系我更改加上。

需要本文数据和代码,可在本文评论区留言。希望对各位兄弟姐妹们有所帮助。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有